package sostats.core.base;
public class Path{
	private final static String PATH_SEPARATOR=".";
	private final static Path END_VALUE=new Path();
	private final String val;
	private final Path last;
	private final int size;
	public static Path newInstance(){
		return END_VALUE;
	}
	private Path(){
		this.val = "";
		this.size = 0;
		this.last = null;
	}
	private Path(String val,Path last){
		this.val = val;
		this.size = last.size()+1;
		this.last = last;
	}
	public String endValue(){
		return val;
	}
	public Path append(String val){
		if(val.indexOf(PATH_SEPARATOR)!=-1) 
			throw new IllegalArgumentException("the value '"+val+"' can't be turned into a path");
		return new Path(val,this);
	}
	private StringBuilder build0(){
		if(this==END_VALUE) return new StringBuilder();
		return last.build0().append(val).append(PATH_SEPARATOR);
	}
	public String build(){
		StringBuilder pathString = this.build0();
		if(pathString.length()==0) return "";
		return pathString.substring(0,pathString.length()-PATH_SEPARATOR.length()).toString();
	}
	public static Path valueOf(String pathString) {
		String[] parts = pathString.split("\\.");
		Path path = END_VALUE;
		for(String part:parts){
			if(!part.isEmpty()) path= path.append(part);
		}
		if(path.size()==0) 
			throw new IllegalArgumentException("the path "+pathString+" string can't be parsed into any paths");
		return path;
	}
	public int size() {
		return this.size;
	}
	public Path suffixPath(int n){
		if(size<n) 
			throw new IndexOutOfBoundsException("the index:"+n+" is larger than the path size:"+size);
		Path path = Path.newInstance();
		Path cur = this;
		while(n-->0){
			path = path.append(cur.val);
			cur = cur.last;
		}
		return path.reverse();
	}
	public Path prefixPath(int n){
		if(size<n) 
			throw new IndexOutOfBoundsException("the index:"+n+" is larger than the path size:"+size);
		Path cur = this;
		while(n++<size) cur = cur.last;
		return cur;
	}
	public Path reverse(){
		Path  res = END_VALUE;
		Path cur = this;
		while(cur!=END_VALUE){
			res = res.append(cur.val);
			cur = cur.last;
		}
		return res;
	}
	public Path commomPrefix(Path path){
		Path rSelf= this.reverse();
		Path rPath = path.reverse();
		int size = Math.min(rSelf.size(),rPath.size());
		Path res = END_VALUE;
		while(size-->0&&rSelf.val.equals(rPath.val)){
			res= res.append(rSelf.val);
			rSelf = rSelf.last;
			rPath = rPath.last;
		}
		return res;
	}
	public Path backOne(){
		return prefixPath(size-1);
	}
	public Path removePrefix(Path prefix){
		return suffixPath(this.size-prefix.size);
	} 
}
